#ifndef STMT_H
#define STMT_H

#include "expr.h"
#include <vector>

class FunctionSymbol;
class BlockSymbol;
class Context;

class Statement : public Tree{
private:
public:
    Statement(){};
    void    accept(Visitor* v);
    void    evalStatement();
};

class Block : public Tree{
public:
    std::vector<Tree*> statements;
    BlockSymbol *blockSym;
    void    accept(Visitor* v);
    Block():blockSym(0){};
};

/// the whole file program
class Program : public Tree{
public:
    Block   *block;

    /// the out-most context
    static  Context     *globalContext;

    Program(Block *blk):block(blk){};
    void    accept(Visitor *v);
};

class VariableDeclareStatement : public Statement{
public:
    int type;
    VariableExpr *varExpr;
public:
    VariableDeclareStatement(int t,VariableExpr *vexpr):type(t),varExpr(vexpr){};
    void    accept(Visitor* v);
};

class AssignmentStatement : public Statement{
public:
    Tree *lhs,*rhs;
    AssignmentStatement(Tree *l,Tree *r):lhs(l),rhs(r){};
    ~AssignmentStatement(){};
    void    accept(Visitor* v);
};

class ParameterListStatement : public Statement{
public:
    std::vector<VariableExpr*> variables;
    void    accept(Visitor* v);
};

class VariableListStatement : public Statement{
public:
    std::vector<VariableExpr*> variables;
    void    accept(Visitor* v);
};

class ExprListStatement : public Statement{
public:
    std::vector<Expr*> variables;
    void    accept(Visitor* v);
};

class FunctionDefStatement : public Statement{
public:
    FunctionNameExpr *funcName;
    ParameterListStatement  *paraList;
    Block            *funcBody;

    FunctionDefStatement(FunctionNameExpr *n,ParameterListStatement *p,Block *b):\
        funcName(n),paraList(p),funcBody(b){};
    void    accept(Visitor* v);
};

class FunctionCallStatement : public Statement{
public:
    FunctionNameExpr *funcName;
    ExprListStatement  *exprList;

    FunctionCallStatement(FunctionNameExpr *n,ExprListStatement *e):\
        funcName(n),exprList(e){};
    void    accept(Visitor* v);
};

class WhileStatement : public Statement{
public:
    Expr    *expr;
    Block	*whileBody;

    WhileStatement(Expr *e,Block *block):
        expr(e),whileBody(block){};
    void    accept(Visitor* v);
};

class IfStatement : public Statement{
public:
    Expr    *expr;
    Block   *ifBlock,*elseBlock;

    IfStatement(Expr *e,Block *blk1,Block *blk2):
        expr(e),ifBlock(blk1),elseBlock(blk2){};
    void    accept(Visitor* v);
};

#endif // STMT_H

